package com.example.service.impl;

import com.example.entity.ChatSession;
import com.example.service.ChatSessionService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 聊天会话管理服务实现类
 * 使用Redis存储会话数据，支持分布式部署
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ChatSessionServiceImpl implements ChatSessionService {

    private final RedisTemplate<String, Object> redisTemplate;
    private final ObjectMapper objectMapper;

    // Redis键前缀
    private static final String SESSION_KEY_PREFIX = "chat:session:";
    private static final String USER_SESSIONS_KEY_PREFIX = "chat:user:sessions:";
    private static final String DEFAULT_SESSION_KEY_PREFIX = "chat:user:default:";
    
    // 会话默认过期时间（24小时）
    private static final long DEFAULT_SESSION_EXPIRE_HOURS = 24;

    /**
     * 创建新的聊天会话
     * @param userId 用户ID
     * @return 新创建的会话
     */
    @Override
    public ChatSession createSession(Long userId) {
        String sessionId = UUID.randomUUID().toString();
        ChatSession session = new ChatSession();
        session.setSessionId(sessionId);
        session.setUserId(userId);
        session.setCreateTime(LocalDateTime.now());
        session.setLastActiveTime(LocalDateTime.now());
        session.setStatus("ACTIVE");
        
        // 添加系统消息
        session.addMessage("system", session.getConfig().getSystemPrompt());
        
        // 保存会话
        saveSession(session);
        
        // 添加到用户会话列表
        addToUserSessionList(userId, sessionId);
        
        log.info("为用户 {} 创建新会话: {}", userId, sessionId);
        return session;
    }

    /**
     * 获取用户的会话
     * @param userId 用户ID
     * @param sessionId 会话ID
     * @return 会话信息
     */
    @Override
    public Optional<ChatSession> getSession(Long userId, String sessionId) {
        try {
            String key = SESSION_KEY_PREFIX + sessionId;
            String sessionJson = (String) redisTemplate.opsForValue().get(key);
            
            if (sessionJson == null) {
                log.debug("会话不存在: {}", sessionId);
                return Optional.empty();
            }
            
            ChatSession session = objectMapper.readValue(sessionJson, ChatSession.class);
            
            // 验证会话归属
            if (!userId.equals(session.getUserId())) {
                log.warn("用户 {} 尝试访问不属于自己的会话 {}", userId, sessionId);
                return Optional.empty();
            }
            
            // 检查会话是否过期
            if (session.isExpired()) {
                log.info("会话已过期: {}", sessionId);
                deleteSession(userId, sessionId);
                return Optional.empty();
            }
            
            return Optional.of(session);
            
        } catch (JsonProcessingException e) {
            log.error("解析会话数据失败: {}", sessionId, e);
            return Optional.empty();
        }
    }

    /**
     * 获取用户的所有活跃会话列表
     * @param userId 用户ID
     * @return 用户的会话列表
     */
    @Override
    public List<ChatSession> getUserSessions(Long userId) {
        try {
            String userSessionsKey = USER_SESSIONS_KEY_PREFIX + userId;
            Set<Object> sessionIds = redisTemplate.opsForSet().members(userSessionsKey);
            
            if (sessionIds == null || sessionIds.isEmpty()) {
                return new ArrayList<>();
            }
            
            List<ChatSession> sessions = new ArrayList<>();
            for (Object sessionIdObj : sessionIds) {
                String sessionId = (String) sessionIdObj;
                Optional<ChatSession> sessionOpt = getSession(userId, sessionId);
                sessionOpt.ifPresent(sessions::add);
            }
            
            // 按最后活跃时间倒序排序
            sessions.sort((s1, s2) -> s2.getLastActiveTime().compareTo(s1.getLastActiveTime()));
            
            return sessions;
            
        } catch (Exception e) {
            log.error("获取用户会话列表失败: {}", userId, e);
            return new ArrayList<>();
        }
    }

    /**
     * 保存会话信息
     * @param session 会话对象
     */
    @Override
    public void saveSession(ChatSession session) {
        try {
            String key = SESSION_KEY_PREFIX + session.getSessionId();
            String sessionJson = objectMapper.writeValueAsString(session);
            
            // 设置过期时间
            redisTemplate.opsForValue().set(key, sessionJson, 
                session.getConfig().getSessionExpiryHours(), TimeUnit.HOURS);
            
            log.debug("保存会话: {}", session.getSessionId());
            
        } catch (JsonProcessingException e) {
            log.error("序列化会话数据失败: {}", session.getSessionId(), e);
        }
    }

    /**
     * 添加消息到指定会话
     * @param userId 用户ID
     * @param sessionId 会话ID
     * @param role 消息角色
     * @param content 消息内容
     * @return 更新后的会话
     */
    @Override
    public ChatSession addMessage(Long userId, String sessionId, String role, String content) {
        Optional<ChatSession> sessionOpt = getSession(userId, sessionId);
        
        if (sessionOpt.isEmpty()) {
            throw new RuntimeException("会话不存在或已过期: " + sessionId);
        }
        
        ChatSession session = sessionOpt.get();
        session.addMessage(role, content);
        
        // 更新会话标题（基于第一条用户消息）
        if ("user".equals(role)) {
            session.updateTitle();
        }
        
        saveSession(session);
        
        log.debug("向会话 {} 添加消息，角色: {}", sessionId, role);
        return session;
    }

    /**
     * 删除会话
     * @param userId 用户ID
     * @param sessionId 会话ID
     * @return 是否删除成功
     */
    @Override
    public boolean deleteSession(Long userId, String sessionId) {
        try {
            // 验证会话归属
            Optional<ChatSession> sessionOpt = getSession(userId, sessionId);
            if (sessionOpt.isEmpty()) {
                return false;
            }
            
            // 删除会话数据
            String sessionKey = SESSION_KEY_PREFIX + sessionId;
            redisTemplate.delete(sessionKey);
            
            // 从用户会话列表中移除
            removeFromUserSessionList(userId, sessionId);
            
            // 如果是默认会话，也要清除默认会话记录
            String defaultSessionKey = DEFAULT_SESSION_KEY_PREFIX + userId;
            String defaultSessionId = (String) redisTemplate.opsForValue().get(defaultSessionKey);
            if (sessionId.equals(defaultSessionId)) {
                redisTemplate.delete(defaultSessionKey);
            }
            
            log.info("删除用户 {} 的会话: {}", userId, sessionId);
            return true;
            
        } catch (Exception e) {
            log.error("删除会话失败: {}", sessionId, e);
            return false;
        }
    }

    /**
     * 归档会话
     * @param userId 用户ID
     * @param sessionId 会话ID
     * @return 是否归档成功
     */
    @Override
    public boolean archiveSession(Long userId, String sessionId) {
        try {
            Optional<ChatSession> sessionOpt = getSession(userId, sessionId);
            if (sessionOpt.isEmpty()) {
                return false;
            }
            
            ChatSession session = sessionOpt.get();
            session.setStatus("ARCHIVED");
            saveSession(session);
            
            log.info("归档用户 {} 的会话: {}", userId, sessionId);
            return true;
            
        } catch (Exception e) {
            log.error("归档会话失败: {}", sessionId, e);
            return false;
        }
    }

    /**
     * 清理过期会话
     * @return 清理的会话数量
     */
    @Override
    public int cleanupExpiredSessions() {
        // 这个功能需要通过定时任务来执行
        // 由于Redis的过期机制，大部分过期会话会自动清理
        // 这里主要是清理用户会话列表中的过期引用
        
        int cleanedCount = 0;
        try {
            Set<String> userSessionKeys = redisTemplate.keys(USER_SESSIONS_KEY_PREFIX + "*");
            if (userSessionKeys != null) {
                for (String userSessionKey : userSessionKeys) {
                    String userIdStr = userSessionKey.substring(USER_SESSIONS_KEY_PREFIX.length());
                    Long userId = Long.parseLong(userIdStr);
                    
                    Set<Object> sessionIds = redisTemplate.opsForSet().members(userSessionKey);
                    if (sessionIds != null) {
                        for (Object sessionIdObj : sessionIds) {
                            String sessionId = (String) sessionIdObj;
                            String sessionKey = SESSION_KEY_PREFIX + sessionId;
                            
                            // 检查会话是否还存在
                            if (!redisTemplate.hasKey(sessionKey)) {
                                removeFromUserSessionList(userId, sessionId);
                                cleanedCount++;
                            }
                        }
                    }
                }
            }
            
            log.info("清理了 {} 个过期会话引用", cleanedCount);
            
        } catch (Exception e) {
            log.error("清理过期会话失败", e);
        }
        
        return cleanedCount;
    }

    /**
     * 获取用户的默认会话（如果不存在则创建）
     * @param userId 用户ID
     * @return 默认会话
     */
    @Override
    public ChatSession getOrCreateDefaultSession(Long userId) {
        String defaultSessionKey = DEFAULT_SESSION_KEY_PREFIX + userId;
        String defaultSessionId = (String) redisTemplate.opsForValue().get(defaultSessionKey);
        
        if (defaultSessionId != null) {
            Optional<ChatSession> sessionOpt = getSession(userId, defaultSessionId);
            if (sessionOpt.isPresent()) {
                return sessionOpt.get();
            }
        }
        
        // 创建新的默认会话
        ChatSession newSession = createSession(userId);
        newSession.setTitle("默认对话");
        saveSession(newSession);
        
        // 设置为默认会话
        redisTemplate.opsForValue().set(defaultSessionKey, newSession.getSessionId(), 
            DEFAULT_SESSION_EXPIRE_HOURS, TimeUnit.HOURS);
        
        return newSession;
    }

    /**
     * 更新会话配置
     * @param userId 用户ID
     * @param sessionId 会话ID
     * @param config 新的配置
     * @return 是否更新成功
     */
    @Override
    public boolean updateSessionConfig(Long userId, String sessionId, ChatSession.SessionConfig config) {
        try {
            Optional<ChatSession> sessionOpt = getSession(userId, sessionId);
            if (sessionOpt.isEmpty()) {
                return false;
            }
            
            ChatSession session = sessionOpt.get();
            session.setConfig(config);
            saveSession(session);
            
            log.info("更新用户 {} 会话 {} 的配置", userId, sessionId);
            return true;
            
        } catch (Exception e) {
            log.error("更新会话配置失败: {}", sessionId, e);
            return false;
        }
    }

    /**
     * 重命名会话
     * @param userId 用户ID
     * @param sessionId 会话ID
     * @param newTitle 新标题
     * @return 是否重命名成功
     */
    @Override
    public boolean renameSession(Long userId, String sessionId, String newTitle) {
        try {
            // 参数验证
            if (newTitle == null || newTitle.trim().isEmpty()) {
                log.warn("重命名会话失败：新标题为空 - 用户: {}, 会话: {}", userId, sessionId);
                return false;
            }
            
            Optional<ChatSession> sessionOpt = getSession(userId, sessionId);
            if (sessionOpt.isEmpty()) {
                log.warn("重命名会话失败：会话不存在 - 用户: {}, 会话: {}", userId, sessionId);
                return false;
            }
            
            ChatSession session = sessionOpt.get();
            String trimmedTitle = newTitle.trim();
            
            // 检查标题是否有变化
            if (trimmedTitle.equals(session.getTitle())) {
                log.info("会话标题未变化，直接返回成功 - 用户: {}, 会话: {}, 标题: '{}'", 
                        userId, sessionId, trimmedTitle);
                return true;
            }
            
            session.setTitle(trimmedTitle);
            session.setLastActiveTime(LocalDateTime.now());
            saveSession(session);
            
            log.info("重命名用户 {} 会话 {} 为: {}", userId, sessionId, trimmedTitle);
            return true;
            
        } catch (Exception e) {
            log.error("重命名会话失败: {} - 用户: {}, 会话: {}, 新标题: '{}'", 
                    e.getMessage(), userId, sessionId, newTitle, e);
            return false;
        }
    }

    /**
     * 添加会话到用户会话列表
     * @param userId 用户ID
     * @param sessionId 会话ID
     */
    private void addToUserSessionList(Long userId, String sessionId) {
        String userSessionsKey = USER_SESSIONS_KEY_PREFIX + userId;
        redisTemplate.opsForSet().add(userSessionsKey, sessionId);
        redisTemplate.expire(userSessionsKey, DEFAULT_SESSION_EXPIRE_HOURS, TimeUnit.HOURS);
    }

    /**
     * 从用户会话列表中移除会话
     * @param userId 用户ID
     * @param sessionId 会话ID
     */
    private void removeFromUserSessionList(Long userId, String sessionId) {
        String userSessionsKey = USER_SESSIONS_KEY_PREFIX + userId;
        redisTemplate.opsForSet().remove(userSessionsKey, sessionId);
    }
} 